Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | import type { APIContext, GetStaticPaths } from "astro";
import { getCollection } from "astro:content";
import { generateOgImage, generateOgImageForIndex } from "../../lib/og-image";
export const getStaticPaths: GetStaticPaths = async () => {
const posts = await getCollection("blog");
const sorted = posts.sort(
(a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(),
);
const paths: { params: { path: string }; props: { title: string } }[] = [];
// 記事ページ
for (const post of posts) {
paths.push({
params: { path: post.slug },
props: { title: post.data.title },
});
}
// タグページ
const allTags = [
...new Set(posts.flatMap((p) => p.data.tags || []).filter(Boolean)),
];
for (const tag of allTags) {
paths.push({
params: { path: `tag/${tag}` },
props: { title: `${tag} の記事一覧` },
});
}
// 年別ページ
const years = [
...new Set(
posts.map((p) => new Date(p.data.date).getFullYear().toString()),
),
];
for (const year of years) {
const count = posts.filter(
(p) => new Date(p.data.date).getFullYear().toString() === year,
).length;
paths.push({
params: { path: year },
props: { title: `${year}年の記事 (${count}件)` },
});
}
// 月別ページ
const yearMonths = new Set<string>();
posts.forEach((post) => {
const d = new Date(post.data.date);
const year = d.getFullYear().toString();
const month = String(d.getMonth() + 1).padStart(2, "0");
yearMonths.add(`${year}/${month}`);
});
for (const ym of yearMonths) {
const [year, month] = ym.split("/");
const count = posts.filter((p) => {
const d = new Date(p.data.date);
return (
d.getFullYear().toString() === year &&
String(d.getMonth() + 1).padStart(2, "0") === month
);
}).length;
paths.push({
params: { path: `${year}/${month}` },
props: { title: `${year}年${month}月の記事 (${count}件)` },
});
}
// ページネーション(1ページ10件、ページ1はindex、ページ2以降がpages/N)
const POSTS_PER_PAGE = 10;
const totalPages = Math.ceil(sorted.length / POSTS_PER_PAGE);
for (let page = 2; page <= totalPages; page++) {
paths.push({
params: { path: `pages/${page}` },
props: { title: "tubone BOYAKI" },
});
}
// 静的ページ
paths.push({ params: { path: "index" }, props: { title: "tubone BOYAKI" } });
paths.push({ params: { path: "tags" }, props: { title: "タグ一覧" } });
paths.push({
params: { path: "privacy-policies" },
props: { title: "Privacy Policies" },
});
return paths;
};
export async function GET({ props, params }: APIContext) {
const png =
params.path === "index"
? await generateOgImageForIndex()
: await generateOgImage(props.title as string);
const body = png.buffer.slice(
png.byteOffset,
png.byteOffset + png.byteLength,
) as ArrayBuffer;
return new Response(body, {
headers: { "Content-Type": "image/png" },
});
}
|